/*
* Copyright (C) 2019 ~ 2021 Uniontech Software Technology Co.,Ltd.
*
* Author:     yanghongwei <yanghongwei@uniontech.com>
*
* Maintainer: yanghongwei <yanghongwei@uniontech.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/

#include "notify_manage.h"
#include "fanotify_file_listener.h"
#include "inotify_file_listener.h"

#include <QDebug>
#include <QTimer>
#include <QFileInfo>
#include <QDir>
#include <QDBusAbstractAdaptor>

NotifyManage::NotifyManage(QObject *parent)
    : QObject(parent)
    , m_fanotify(new Fanotify(this))
    , m_inotify(new Inotify(this))
{
    connect(m_fanotify, &Fanotify::operationDir, this, [ & ] (QString dir) {
        m_inotify->setNotifyObject(dir);
    });

    connect(m_fanotify, &Fanotify::operationHappen, this, &NotifyManage::operationHappen);
    connect(m_inotify, &Inotify::operationHappen, this, &NotifyManage::operationHappen);

    QTimer *timer = new QTimer(this);
    connect(timer, &QTimer::timeout, this, &NotifyManage::processNode);
    timer->start(50);
}

void NotifyManage::addUDiskDir(const QString &path)
{
    m_uDiskDirs.append(path);
    initDir(path);
}

void NotifyManage::addRootDir(const QString &path)
{
    m_rootDirs.append(path);
    initDir(path);
}

void NotifyManage::initDir(const QString &path)
{
    m_inotify->setNotifyObject(path);
    m_fanotify->setNotifyObject(path);
}

void NotifyManage::startWatch()
{
    m_inotify->startListen();
    m_fanotify->startListen();
}

void NotifyManage::clearOldData(QList<OperationNode> &nodes, const QDateTime &beforeDate)
{
    QList<OperationNode> nodesTmp = nodes;
    for (auto& node : nodesTmp) {
        if (node.m_date < beforeDate) {
            nodes.removeOne(node);
        }
    }
}

void NotifyManage::operationHappen(OperationNode node)
{
    if (sender() == m_fanotify) {
        m_currentOperator = node.m_operator;
    } else if (sender() == m_inotify) {
        node.m_operator = m_currentOperator;

        if (node.m_operator == "dde-file-manage" || node.m_operator == "cp") {
            if (node.m_operationType == 2) {
                m_inotifyCreateList.append(node);
            } else if (node.m_operationType == 4 && QFileInfo(node.m_fileName).isDir()) {
                m_inotifyCreateList.append(node);
            } else if (node.m_operationType == 10) {
                m_inotifyAccessList.append(node);
            }
        }
    //    qInfo() << "文件【" << node.m_fileName << "】在[" << node.m_date << "]被【" << node.m_operator << "】" << node.m_operationType;
    }
}

QPair<QString, QString>  NotifyManage::copyUDisk(const QString & path1, const QString & path2)
{
    QPair<QString, QString> pair;
    for (const auto &path : m_uDiskDirs) {
        if (pair.first.isEmpty() && path1.contains(path))
            pair.first = path;

        if (pair.second.isEmpty() && path2.contains(path))
            pair.second = path;
    }
    return pair;
}

void NotifyManage::processNode()
{
    // 当前时间往前退500ms
    bool isCreate = !m_inotifyCreateList.isEmpty();
    bool isAccess = !m_inotifyAccessList.isEmpty();

    if (!isCreate && !isAccess)
        return;

    QDateTime currentDate = QDateTime::currentDateTime().addMSecs(-500);
    if (isCreate && isAccess) {
        QList<OperationNode> inotifyAccessList(m_inotifyAccessList);
        QList<OperationNode> inotifyCreateList(m_inotifyCreateList);
        for (auto& node : inotifyCreateList) {
            QFileInfo info(node.m_fileName);
            QString fileName1(info.fileName());
            fileName1.remove(QRegExp("\\(副本 *\\d*\\)"));
            for (auto& nodeAccess : inotifyAccessList) {
                QFileInfo infoAccess(nodeAccess.m_fileName);
                QString fileName2(info.fileName());
                fileName2.remove(QRegExp("\\(副本 *\\d*\\)"));
                if (fileName1 != fileName2)
                    continue;

                if (info.absolutePath() == infoAccess.absolutePath()) {
                    m_inotifyAccessList.removeOne(nodeAccess);
                    break;
                }

                QPair<QString, QString> pair(copyUDisk(info.absolutePath(), infoAccess.absolutePath()));
                if (pair.first != pair.second) {
                    ReportNode reportNode;
                    if (!pair.first.isEmpty()) {
                        qInfo() << "文件【" << info.fileName() << "】在[" << node.m_date << "]被【" << node.m_operator << "】拷入" << info.absolutePath();
                        reportNode.m_fileName = info.fileName();
                        reportNode.m_date = node.m_date.toString("yyyy-MM-dd hh:mm:ss.zzz");
                        reportNode.m_uDiskDir = info.absolutePath();
                        reportNode.m_operation = QString("拷入");
                        saveLocal(reportNode);
                    }
                    if (!pair.second.isEmpty()) {
                        qInfo() << "文件【" << infoAccess.fileName() << "】在[" << nodeAccess.m_date << "]被【" << nodeAccess.m_operator << "】拷出" << infoAccess.absolutePath();
                        reportNode.m_fileName = infoAccess.fileName();
                        reportNode.m_date = nodeAccess.m_date.toString("yyyy-MM-dd hh:mm:ss.zzz");
                        reportNode.m_uDiskDir = infoAccess.absolutePath();
                        reportNode.m_operation = QString("拷出");
                        saveLocal(reportNode);
                    }
                }
                m_inotifyAccessList.removeOne(nodeAccess);
                m_inotifyCreateList.removeOne(node);
                break;
            }
        }
    }
    clearOldData(m_inotifyCreateList, currentDate);
    clearOldData(m_inotifyAccessList, currentDate);
}
